﻿//TODO: Dissolve: This has to be tested

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Image dissolving is based on Alpha Blending.
    /// Alpha blending is the process of combining a translucent foreground color with a
    /// background color, thereby producing a new blended color. The degree of the
    /// foreground color's translucency may range from completely transparent to completely
    /// opaque. If the foreground color is completely transparent, the blended color will be the
    /// background color. Conversely, if it is completely opaque, the blended color will be the
    /// foreground color.        
    /// </summary>
    public class Dissolve : BaseImageFilter, ITwoSourceFilter
    {
        /// <summary>
        /// 
        /// </summary>
        protected int m_nSteps = 10;

        /// <summary>
        /// Initializes a new instance of the <see cref="Dissolve"/> class.
        /// </summary>
        public Dissolve()
            : this(10)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Dissolve"/> class.
        /// </summary>
        /// <param name="_steps">The _steps.</param>
        public Dissolve(int _steps)
        {
            m_nSteps = _steps;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Dissolve"/> class.
        /// </summary>
        /// <param name="_dissolve">The _dissolve.</param>
        internal Dissolve(Dissolve _dissolve)
        {
            m_nSteps = _dissolve.m_nSteps;
        }

        /// <summary>
        /// Gets or sets the steps.
        /// </summary>
        /// <value>The steps.</value>
        public int Steps
        {
            get { return m_nSteps; }
            set { m_nSteps = value; }
        }

        /// <summary>
        /// Processes the specified bmpimg.
        /// </summary>
        /// <param name="bmpimg">The bmpimg.</param>
        /// <param name="bmp">The BMP.</param>
        /// <returns></returns>
        public UnsafeBitmap Process(UnsafeBitmap bmpimg, UnsafeBitmap bmp)
        {
            BitmapData bmpData = bmpimg.BitmapData; //bmpimg.LockBits(new Rectangle(0, 0, bmpimg.Width, bmpimg.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData bmpData2 = bmp.BitmapData; // bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            int width = bmpData.Width;
            int nSteps = m_nSteps;
            int height = bmpData.Height;

            if (bmpData2.Width > width)
                width = bmpData2.Width;
            if (bmpData2.Height > height)
                height = bmpData2.Height;

            UnsafeBitmap bit1 = bmpimg;
            UnsafeBitmap bit2 = bmp;

            UnsafeBitmap bmpresult = new Bitmap(width, height);

            BitmapData data1 = bit1.BitmapData; //bit1.LockBits(new Rectangle(0, 0, bit1.Width, bit1.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData data2 = bit2.BitmapData; //bit2.LockBits(new Rectangle(0, 0, bit2.Width, bit2.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
            BitmapData data3 = bmpresult.BitmapData; //bmpresult.LockBits(new Rectangle(0, 0, bmpresult.Width, bmpresult.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            unsafe
            {
                int remain1 = data1.Stride - data1.Width * 3;
                int remain2 = data2.Stride - data2.Width * 3;
                int remain3 = data3.Stride - data3.Width * 3;

                for (double dAlpha = 1.0; dAlpha > 0.0; dAlpha -= (1.0 / ((double)(nSteps))))
                {
                    byte* ptr1 = (byte*)data1.Scan0;
                    byte* ptr2 = (byte*)data2.Scan0;
                    byte* ptr3 = (byte*)data3.Scan0;
                    for (int i = 0; i < height; i++)
                    {
                        for (int j = 0; j < width * 3; j++)
                        {
                            ptr3[0] = (byte)(dAlpha * ptr1[0] + (1 - dAlpha) * ptr2[0]);
                            ptr1++;
                            ptr2++;
                            ptr3++;
                        }

                        ptr1 += remain1;
                        ptr2 += remain2;
                        ptr3 += remain3;
                    }
                }
            }

            bmpresult.Dispose();

            return bmpresult;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Dissolve(this);
        }
    }
}
